package com.chensi.dao.impl;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import com.chensi.dao.ICommonDao;
@Repository
public class CommonDaoImpl implements ICommonDao{
	@Autowired
	@Qualifier("sessionFactory")
	private SessionFactory sessionFactory;

	/**
	 * 获取当前Session
	 */
	public Session getSession() {
		// 事务必须是开启的(Required)，否则获取不到
		return sessionFactory.getCurrentSession();
	}

	/**
	 * 根据Id获取实体对象
	 * @param entityClass 实体类型
	 * @param id 实体对象主键
	 * @return 查询结果对象
	 */
	public <T> T get(Class<T> entityClass, Serializable id) {
		return (T) getSession().get(entityClass, id);
	}

	/**
	 * 获取实体类的所有数据集合
	 * @param entityClass 实体类型
	 * @return 所有数据集合
	 */
	public <T> List<T> getAll(Class<T> entityClass) {
		return createCriteria(entityClass).list();
	}

	/**
	 * 按属性查找对象列表.
	 */
	public <T> List<T> findByProperty(Class<T> entityClass, String propertyName, Object value) {
		return createCriteria(entityClass, Restrictions.eq(propertyName, value)).list();
	}
	
	public <T> List<T> find(String hql){
		return getSession().createQuery(hql).list();
	}

	/**
	 * 通过HQL和参数查询列表
	 * @param hql 查询hql
	 * @return params 参数
	 */
	public <T> List<T> findByHql(String hql, Object... params) {
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		return query.list();
	}

	/**
	 * 通过SQL和参数查询列表
	 * @param sql 查询sql
	 * @return 查询结果列表
	 */
	public <T> List<T> findBySql(String sql) {
		return findBySql(sql, null);
	}

	/**
	 * 通过SQL和参数查询列表
	 * @param sql 查询sql
	 * @param params 参数
	 * @return 查询结果列表
	 */
	public <T> List<T> findBySql(String sql, Object[] params) {
		SQLQuery query = getSession().createSQLQuery(sql);
		if (params == null || params.length == 0) {
			return query.list();
		}
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		return query.list();
	}

	/**
	 * 通过SQL和参数查询列表
	 * @param sql 查询sql
	 * @param entityClass 查询结果实体类型
	 * @return 查询结果列表
	 */
	public <T> List<T> findBySql(Class<T> entityClass, String sql) {
		return findBySql(entityClass, sql, null);
	}

	/**
	 * 通过SQL和参数查询列表
	 * @param entityClass 查询结果实体类型
	 * @param sql 查询sql
	 * @param params 参数
	 * @return 查询结果列表
	 */
	public <T> List<T> findBySql(Class<T> entityClass, String sql, Object[] params) {
		SQLQuery query = getSession().createSQLQuery(sql);
		query.addEntity(entityClass);
		if (params == null || params.length == 0) {
			return query.list();
		}
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		return query.list();
	}

	/**
	 * 保存实体对象
	 * @param entity 实体对象
	 */
	public <T> void save(T entity) {
		getSession().save(entity);
		getSession().flush();
	}

	/**
	 * 保存实体对象集合
	 * @param entitys 实体对象集合
	 */
	public <T> void saveAll(Collection<T> entitys) {
		Iterator<T> iterator = entitys.iterator();
		int index = 0;
		while (iterator.hasNext()) {
			index++;
			T entity = iterator.next();
			getSession().save(entity);
			if (index % 20 == 0) {
				// 20个对象后才清理缓存，写入数据库
				getSession().flush();
				getSession().clear();
			}
		}
		if (index % 20 != 0) {
			// 最后清理一下大于20小于40的部分
			getSession().flush();
			getSession().clear();
		}
	}

	/**
	 * 保存或更新实体对象
	 * @param entity 实体对象
	 */
	public <T> void saveOrUpdate(T entity) {
		getSession().saveOrUpdate(entity);
		getSession().flush();
	}

	/**
	 * 更新指定的实体
	 */
	public <T> void update(T entity) {
		getSession().update(entity);
		getSession().flush();
	}

	/**
	 * 更新实体对象集合
	 * @param entitys 实体对象集合
	 */
	public <T> void updateAll(Collection<T> entitys) {
		Iterator<T> iterator = entitys.iterator();
		int index = 0;
		while (iterator.hasNext()) {
			index++;
			T entity = iterator.next();
			getSession().update(entity);
			if (index % 20 == 0) {
				// 20个对象后才清理缓存，写入数据库
				getSession().flush();
				getSession().clear();
			}
		}
		if (index % 20 != 0) {
			// 最后清理一下大于20小于40的部分
			getSession().flush();
			getSession().clear();
		}
	}

	/**
	 * 删除实体对象对应的数据库记录
	 * @param entity 实体对象
	 */
	public <T> void delete(T entity) {
		getSession().delete(entity);
		getSession().flush();
	}

	/**
	 * 根据主键删除实体对象
	 * @param entityClass 实体对象类型
	 * @param id 主键
	 */
	public <T> void deleteById(Class<T> entityClass, Serializable id) {
		if (id == null) {
			return;
		}
		T entity = get(entityClass, id);
		if (entity != null) {
			getSession().delete(entity);
			getSession().flush();
		}
	}

	/**
	 * 删除实体对象集合
	 * @param entitys 实体对象集合
	 */
	public <T> void deleteAll(Collection<T> entitys) {
		if (entitys == null || entitys.isEmpty()) {
			return;
		}
		Iterator<T> iterator = entitys.iterator();
		int index = 0;
		while (iterator.hasNext()) {
			index++;
			T entity = iterator.next();
			getSession().delete(entity);
			if (index % 20 == 0) {
				// 20个对象后才清理缓存，写入数据库
				getSession().flush();
				getSession().clear();
			}
		}
		if (index % 20 != 0) {
			// 最后清理一下大于20小于40的部分
			getSession().flush();
			getSession().clear();
		}
	}

	/**
	 * 根据实体类创建查询实体
	 * @param entityClass 实体类型
	 * @return 查询实体
	 */
	public Criteria createCriteria(Class entityClass) {
		return getSession().createCriteria(entityClass);
	}

	/**
	 * 创建带查询实体集合的查询实体对象
	 * @param entityClass 实体类型
	 * @param criterions 查询参数集合
	 * @return 查询实体
	 */
	public <T> Criteria createCriteria(Class<T> entityClass, Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(entityClass);
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		return criteria;
	}
}
